﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Timers;
using System.Text.RegularExpressions;


namespace SerialTool
{
    public partial class Form1 : Form
    {
        // 状态条更新定时器
        System.Timers.Timer statusTimer = new System.Timers.Timer();
        // 自动发送定时器
        System.Timers.Timer autoSendTimer = new System.Timers.Timer();

        // 串口
        private SerialPort serialPort;
        private bool isReceiving, isSending, isClosing;
        private int sendCnt = 0, recCnt = 0;

        public Form1()
        {
            InitializeComponent();
        }



        private void Form1_Load(object sender, EventArgs e)
        {
            // 刷新串口列表
            combComName.Items.AddRange(SerialPort.GetPortNames());
            //combComName.SelectedIndex = 0;

            // 初始化常用波特率
            string[] strBaudRate = new string[] {"1200", "2400", "4800", "9600", "14400", "19200", "38400",
                                         "56000", "57600", "115200"};
            comboBuadrate.DataSource = strBaudRate;
            comboBuadrate.SelectedIndex = 9;

            // 初始化数据位
            string[] strDataBit = new string[] { "8", "7", "6", "5"};
            comboDataBits.DataSource = strDataBit;
            comboDataBits.SelectedIndex = 0;

            // 初始化停止位
            string[] strStopBit = new string[] { "1", "1.5", "2"};
            comboStopBits.DataSource = strStopBit;
            comboStopBits.SelectedIndex = 0;

            // 初始化校验位
            string[] strParity = new string[] {"无", "奇校验", "偶校验"};
            comboParity.DataSource = strParity;
            comboParity.SelectedIndex = 0;

            // 状态栏定时器初始化   获取windows时间并显示
            statusLabelTime.Text = "当前时间：" + DateTime.Now.ToLongTimeString().ToString();
            statusTimer.Elapsed += new ElapsedEventHandler(UpdateStatusTime);
            statusTimer.Interval = 100;
            statusTimer.AutoReset = true;
            statusTimer.Enabled = true;

            // 打开关闭串口初始化
            serialPort = new SerialPort
            {
                Encoding = System.Text.Encoding.GetEncoding("gb2312")
            };

            serialPort.DataReceived += new SerialDataReceivedEventHandler(ReadData);
            isReceiving = false;
            isSending = false;
            isClosing = false;
            sendCnt = 0;
            recCnt = 0;

            // 自动发送定时器初始化
            autoSendTimer.Elapsed += new ElapsedEventHandler(BtnSend_Click);
            autoSendTimer.Interval = 1000;
            autoSendTimer.AutoReset = true;
            autoSendTimer.Enabled = false;
        }

        // 更新状态栏函数
        private void UpdateStatusTime(object sender, System.Timers.ElapsedEventArgs e)
        {
            try
            {
                this.BeginInvoke(new Action(() =>
                                        {
                                            statusLabelTime.Text = "当前时间：" + DateTime.Now.ToLongTimeString().ToString();
                                            statusLabelSendCnt.Text = string.Format("发送：{0,6}", sendCnt);
                                            statusLabelRecCnt.Text = string.Format("接收：{0,6}", recCnt);
                                        }));
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "ERROR");
            }
            
        }

        // 接收数据
        private void ReadData(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            try
            {
                // 正在执行关闭动作，不必读串口，立即返回
                if (isClosing)
                {
                    return;
                }

                if (serialPort.IsOpen)
                {
                    isReceiving = true; // 标记正在执行接收动作
                    this.Invoke((EventHandler)(delegate
                    {
                        int num = serialPort.BytesToRead;
                        recCnt += num;
                        //if (txtbDisplay.TextLength > 100000)    // 设置自动清空显示
                        //{
                        //    txtbDisplay.Text = "";
                        //}
                        
                        if (chkHexDisplay.Checked)  //hex 接收显示
                        {
                            byte[] recbyte = new byte[num];
                            StringBuilder sb = new StringBuilder(20);
                            serialPort.Read(recbyte, 0, num);
                            foreach (byte b in recbyte)
                            {
                                sb.Append( string.Format("{0:X2} ", b));
                            }
                            txtbDisplay.AppendText(sb.ToString());
                        }
                        else  // 字符串接收显示
                        {
                            txtbDisplay.AppendText(serialPort.ReadExisting());
                        }
                        
                    }));
                }

                
            }
            catch (Exception ex)
            {
                System.Media.SystemSounds.Beep.Play();
                MessageBox.Show(ex.Message, "ERROR");
            }
            finally
            {
                isReceiving = false;    // 接收动作完成
            }
        }

        // 发送
        private void BtnSend_Click(object sender, EventArgs e)
        {
            try
            {
                if (isClosing)
                {
                    return;
                }

                if (serialPort.IsOpen)
                {
                    isSending = true;

                    if (chkHexSend.Checked) 
                    {
                        string[] sArray = Regex.Split(txtSend.Text, " ", RegexOptions.IgnoreCase);
                        byte[] b = new byte[sArray.Length];
                        int i = 0;
                        foreach (string str in sArray)
                        {
                            if (str != "")
                            {
                                b[i++] = Convert.ToByte(str, 16);
                                sendCnt += 1;
                            }
                        }
                        serialPort.Write(b, 0, i);
                    }
                    else  // 字符发送
                    {
                        Encoding gb = Encoding.GetEncoding("gb2312");
                        byte[] writebuf = gb.GetBytes(txtSend.Text);
                        serialPort.Write(writebuf, 0, writebuf.Length);
                        sendCnt += writebuf.Length;
                    }
                }
            }
            catch (Exception ex)
            {
                System.Media.SystemSounds.Beep.Play();
                MessageBox.Show(ex.Message, "ERROR");
            }
            finally
            {
                isSending = false;
            }
        }

        // 下拉更新串口列表
        private void CombComName_DropDown(object sender, EventArgs e)
        {
            combComName.Items.Clear();
            combComName.Items.AddRange(SerialPort.GetPortNames());
        }

        // hex发送时检测输入内容是否符合规则
        private void TxtSend_TextChanged(object sender, EventArgs e)
        {
            if (chkHexSend.Checked)
            {
                if (Regex.IsMatch(txtSend.Text, @"[^a-fA-F0-9 ]+"))
                {
                    txtSend.Text = Regex.Replace(txtSend.Text, @"[^a-fA-F0-9 ]*", "");
                    txtSend.Select(txtSend.TextLength, 0);
                    MessageBox.Show("请输入正确格式 0-9,a-f,A-F 例如 03 4E AB", "提示");
                }
            }
        }

        // hex 和 string 的转换
        private void ChkHexSend_CheckedChanged(object sender, EventArgs e)
        {
            if (chkHexSend.Checked)
            {
                string str = txtSend.Text;
                StringBuilder sb = new StringBuilder(20);
                Encoding gb = Encoding.GetEncoding("gb2312");
                byte[] bArray = gb.GetBytes(str);
                foreach (byte b in bArray)
                {
                    sb.Append( string.Format("{0:X2} ", b));
                }
                txtSend.Text = sb.ToString();
            }
            else
            {
                string[] sArray = Regex.Split(txtSend.Text, " ", RegexOptions.IgnoreCase);
                byte[] b = new byte[sArray.Length];
                int i = 0;
                foreach (string str in sArray)
                {
                    if (str != "")
                    {

                        b[i++] = Convert.ToByte(str, 16);
                    }
                }
                Encoding gb = Encoding.GetEncoding("gb2312");
                txtSend.Text = gb.GetString(b);
            }
        }

        // hex 和 string 的转换
        private void ChkHexDisplay_CheckedChanged(object sender, EventArgs e)
        {
            if (chkHexDisplay.Checked)
            {
                string str = txtbDisplay.Text;
                StringBuilder sb = new StringBuilder(20);
                Encoding gb = Encoding.GetEncoding("gb2312");
                byte[] bArray = gb.GetBytes(str);
                foreach (byte b in bArray)
                {
                    sb.Append(string.Format("{0:X2} ", b));
                }
                txtbDisplay.Text = sb.ToString();
            }
            else
            {
                string[] sArray = Regex.Split(txtbDisplay.Text, " ", RegexOptions.IgnoreCase);
                byte[] b = new byte[sArray.Length];
                int i = 0;
                foreach (string str in sArray)
                {
                    if (str != "")
                    {

                        b[i++] = Convert.ToByte(str, 16);
                    }
                }
                Encoding gb = Encoding.GetEncoding("gb2312");
                txtbDisplay.Text = gb.GetString(b);
            }
        }

        private void BtnOpenClose_Click(object sender, EventArgs e)
        {
            try
            {
                if (serialPort.IsOpen)  // 串口已经打开，执行关闭动作
                {

                    autoSendTimer.Stop();
                    isClosing = true;
                    while (isReceiving || isSending) Application.DoEvents(); // 等待串口接收动作完成，否则可能会产生线程死锁
                    serialPort.Close(); // 关闭串口
                    isClosing = false;
                    
                    btnOpenClose.Text = "打开串口";
                    combComName.Enabled = true;
                    comboBuadrate.Enabled = true;
                    comboDataBits.Enabled = true;
                    comboParity.Enabled = true;
                    comboStopBits.Enabled = true;
                }
                else                    // 串口已经关闭，执行打开动作
                {
                    serialPort.PortName = combComName.Text;
                    serialPort.DataBits = Convert.ToInt32(comboDataBits.Text);

                    if (Regex.IsMatch(comboBuadrate.Text, @"^[1-9]{1}\d*$"))  // 匹配正整数
                    {
                        serialPort.BaudRate = Convert.ToInt32(comboBuadrate.Text);
                    }

                    if (comboParity.Text.Equals("无"))
                    {
                        serialPort.Parity = System.IO.Ports.Parity.None;
                    }
                    else if (comboParity.Text.Equals("奇校验"))
                    {
                        serialPort.Parity = System.IO.Ports.Parity.Odd;
                    }
                    else if (comboParity.Text.Equals("偶校验"))
                    {
                        serialPort.Parity = System.IO.Ports.Parity.Even;
                    }

                    if (comboStopBits.Text.Equals("1"))
                    {
                        serialPort.StopBits = System.IO.Ports.StopBits.One;
                    }
                    else if (comboStopBits.Text.Equals("1.5"))
                    {
                        serialPort.StopBits = System.IO.Ports.StopBits.OnePointFive;
                    }
                    else if (comboStopBits.Text.Equals("2"))
                    {
                        serialPort.StopBits = System.IO.Ports.StopBits.Two;
                    }

                    serialPort.Open();
                    btnOpenClose.Text = "关闭串口";
                    combComName.Enabled = false;
                    comboBuadrate.Enabled = false;
                    comboDataBits.Enabled = false;
                    comboParity.Enabled = false;
                    comboStopBits.Enabled = false;

                    if (chkTimingSending.Checked)
                    {
                        autoSendTimer.Start();
                    }
                }
            }
            catch (Exception ex)
            {
                System.Media.SystemSounds.Beep.Play();
                MessageBox.Show(ex.Message, "提示");
            }
            
        }

        private void ChkTimingSending_CheckedChanged(object sender, EventArgs e)
        {
            if (chkTimingSending.Checked)
            {
                if (Regex.IsMatch(txtSendInterval.Text, @"^[1-9]{1}\d*$")) // 匹配正整数
                {
                    autoSendTimer.Interval = Convert.ToInt32(txtSendInterval.Text);
                    autoSendTimer.Start();
                    txtSendInterval.Enabled = false;
                }
                else
                {
                    MessageBox.Show("请输入正整数","提示");
                    chkTimingSending.Checked = false;
                }
            }
            else
            {
                autoSendTimer.Stop();
                txtSendInterval.Enabled = true;
            }
        }

        private void BtnClearDisplay_Click(object sender, EventArgs e)
        {
            txtbDisplay.Text = "";
            sendCnt = 0;
            recCnt = 0;
        }
    }
}
